package com.zaker.touchtv.modules.polling;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.NonNull;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 轮询任务工具类
 *
 * @author zonda
 */
public class PollTask {

  private static final long DEFAULT_PERIODS = 5000;

  private final InternalHandler mHandler = new InternalHandler();

  private volatile Runnable mPollRunnable;

  private volatile ThreadPoolExecutor mPollExecutor;

  private long mPeriods = DEFAULT_PERIODS;

  public PollTask() {

    initPollExecutor();
  }

  public final void executePollTask(@NonNull final Runnable exeRunnable) {

    cancelPollTask();

    mPollRunnable = new Runnable() {
      @Override
      public void run() {
        executeRunnable(exeRunnable);
      }
    };
    mHandler.post(mPollRunnable);
  }

  public final void executePollAsyncTask(@NonNull final Runnable exeRunnable) {

    cancelPollTask();

    mPollRunnable = new Runnable() {
      @Override
      public void run() {
        executeAsyncRunnable(exeRunnable);
      }
    };
    mHandler.post(mPollRunnable);
  }

  public final void destroyPollTask() {
    cancelPollTask();
    destroyPollExecutor();
  }

  public void setPeriods(long periodsMillSeconds) {
    if (periodsMillSeconds < 1000) {
      return;
    }
    mPeriods = periodsMillSeconds;
  }

  private void cancelPollTask() {
    if (mPollRunnable != null) {
      mHandler.removeCallbacks(mPollRunnable);
      mPollRunnable = null;
    }
  }

  private void executeAsyncRunnable(@NonNull final Runnable exeRunnable) {

    initPollExecutor();
    mPollExecutor.execute(new Runnable() {
      @Override
      public void run() {
        executeRunnable(exeRunnable);
      }
    });
  }

  private void executeRunnable(@NonNull final Runnable exeRunnable) {

    exeRunnable.run();
    if (mPollRunnable != null) {
      mHandler.removeCallbacks(mPollRunnable);
      mHandler.postDelayed(mPollRunnable, mPeriods);
    }
  }

  private void initPollExecutor() {

    if (mPollExecutor != null) {
      return;
    }
    mPollExecutor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES,
        new LinkedBlockingQueue<Runnable>(),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.DiscardPolicy());
  }

  private void destroyPollExecutor() {

    if (mPollExecutor == null) {
      return;
    }
    mPollExecutor.shutdown();
    mPollExecutor = null;
  }

  private static class InternalHandler extends Handler {

    InternalHandler() {
      super(Looper.getMainLooper());
    }

    @Override
    public void handleMessage(Message msg) {
      super.handleMessage(msg);
    }
  }
}
